package com.hjq.permissions;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.AbilityLifecycleExecutor;
import ohos.aafwk.ability.AbilitySlice;
import ohos.app.AbilityContext;
import ohos.app.Context;
import ohos.bundle.IBundleManager;
import ohos.rpc.RemoteException;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

final class PermissionUtils {
    /**
     * 返回应用程序在清单文件中注册的权限
     *
     * @param context context
     * @return List<String> List
     */
    static List<String> getManifestPermissions(Context context) {
        try {
            // 当清单文件没有注册任何权限的时候，那么这个数组对象就是空的
            return context.getBundleManager()
                    .getBundleInfo(context.getBundleName(), IBundleManager.GET_BUNDLE_WITH_REQUESTED_PERMISSION)
                    .reqPermissions;
        } catch (RemoteException e) {
            return new ArrayList<>();
        }
    }

    /**
     * 判断某些权限是否全部被授予
     *
     * @param context     context
     * @param permissions permissions
     * @return boolean
     */
    static boolean isPermissionGranted(Context context, List<String> permissions) {
        for (String permission : permissions) {
            if (!isPermissionGranted(context, permission)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断某个权限是否授予
     *
     * @param context    context
     * @param permission permission
     * @return boolean
     */
    static boolean isPermissionGranted(Context context, String permission) {
        return context.verifySelfPermission(permission) == IBundleManager.PERMISSION_GRANTED;
    }

    /**
     * 获取某个权限的状态
     *
     * @param context    context
     * @param permission permission
     * @return 已授权返回  {@link IBundleManager#PERMISSION_GRANTED}
     * 未授权返回  {@link IBundleManager#PERMISSION_DENIED}
     */
    static int getPermissionStatus(Context context, String permission) {
        return PermissionUtils.isPermissionGranted(context, permission)
                ? IBundleManager.PERMISSION_GRANTED
                : IBundleManager.PERMISSION_DENIED;
    }

    /**
     * 在权限组中检查是否有某个权限是否被永久拒绝
     *
     * @param activity    Activity对象
     * @param permissions 请求的权限
     * @return boolean
     */
    static boolean isPermissionPermanentDenied(Ability activity, List<String> permissions) {
        for (String permission : permissions) {
            if (isPermissionPermanentDenied(activity, permission)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断某个权限是否被永久拒绝
     *
     * @param activity   Activity对象
     * @param permission 请求的权限
     * @return boolean
     */
    private static boolean isPermissionPermanentDenied(Ability activity, String permission) {
        return activity.verifySelfPermission(permission) == IBundleManager.PERMISSION_DENIED
                && !activity.canRequestPermission(permission);
    }

    /**
     * 获取没有授予的权限
     *
     * @param permissions  需要请求的权限组
     * @param grantResults 允许结果组
     * @return List<String>
     */
    static List<String> getDeniedPermission(String[] permissions, int[] grantResults) {
        List<String> deniedPermissions = new ArrayList<>();
        for (int i = 0; i < grantResults.length; i++) {
            // 把没有授予过的权限加入到集合中
            if (grantResults[i] != IBundleManager.PERMISSION_GRANTED) {
                deniedPermissions.add(permissions[i]);
            }
        }
        return deniedPermissions;
    }

    /**
     * 获取已授予的权限
     *
     * @param permissions  需要请求的权限组
     * @param grantResults 允许结果组
     * @return List<String>
     */
    static List<String> getGrantedPermission(String[] permissions, int[] grantResults) {
        List<String> grantedPermissions = new ArrayList<>();
        for (int i = 0; i < grantResults.length; i++) {
            // 把授予过的权限加入到集合中
            if (grantResults[i] == IBundleManager.PERMISSION_GRANTED) {
                grantedPermissions.add(permissions[i]);
            }
        }
        return grantedPermissions;
    }

    /**
     * 当前是否运行在 Debug 模式下
     *
     * @param context context
     * @return boolean
     */
    static boolean isDebugMode(Context context) {
        return context.getApplicationInfo() != null && context.getApplicationInfo().debug;
    }

    /**
     * 当前的ability是否处于活跃状态
     *
     * @param ability ability
     * @return boolean
     */
    static boolean isAbilityActive(Ability ability) {
        if (ability == null) {
            return false;
        }
        return ability.getState().getValue() == AbilityLifecycleExecutor.LifecycleState.ACTIVE.getValue();
    }

    /**
     * <p>
     * 这里解释一下为什么不用 Arrays.asList
     * 第一是返回的类型不是 java.util.ArrayList 而是 java.util.Arrays.ArrayList
     * 第二是返回的 ArrayList 对象是只读的，也就是不能添加任何元素，否则会抛异常
     *
     * @param array array
     * @return 将数组转换成 ArrayList
     */
    static <T> ArrayList<T> asArrayList(T... array) {
        ArrayList<T> list = null;
        if (array != null) {
            list = new ArrayList<>(array.length);
            for (T tt : array) {
                list.add(tt);
            }
        }
        return list;
    }

    /**
     * check permissions
     *
     * @param ability            ability对象
     * @param requestPermissions 请求的权限组
     */
    static void checkPermissionManifest(Ability ability, List<String> requestPermissions) {
        List<String> manifestPermissions = getManifestPermissions(ability);
        if (manifestPermissions == null || manifestPermissions.isEmpty()) {
            throw new ManifestException();
        }

        for (String permission : requestPermissions) {
            if (!manifestPermissions.contains(permission)) {
                throw new ManifestException(permission);
            }
        }
    }

    /**
     * 获得随机的 RequestCode
     *
     * @return int
     */
    static int getRandomRequestCode() {
        // 请求码必须在 2 的 16 次方以内 SecureRandom
        return new SecureRandom().nextInt((int) Math.pow(2, 16));
    }

    /**
     * 获取上下文中的 Activity 对象
     *
     * @param context context
     * @return Ability
     */
    static Ability getActivity(Context context) {
        Context ctx = context;
        do {
            if (ctx instanceof Ability) {
                return (Ability) ctx;
            } else if (ctx instanceof AbilitySlice) {
                ctx = ((AbilitySlice) ctx).getAbility();
            } else if (ctx instanceof AbilityContext) {
                ctx = ((AbilityContext) ctx).getContext();
            } else {
                return null;
            }
        } while (ctx != null);
        return null;
    }
}
